home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gxclrect.c < prev    next >
C/C++ Source or Header  |  1997-03-11  |  16KB  |  567 lines

  1. /* Copyright (C) 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gxclrect.c */
  20. /* Rectangle-oriented command writing for command list */
  21. #include "gx.h"
  22. #include "gserrors.h"
  23. #include "gsutil.h"            /* for gs_next_ids */
  24. #include "gxdevice.h"
  25. #include "gxdevmem.h"            /* must precede gxcldev.h */
  26. #include "gxcldev.h"
  27.  
  28. #define cdev cwdev
  29.  
  30. /* ---------------- Writing utilities ---------------- */
  31.  
  32. #define cmd_set_rect(rect)\
  33.   ((rect).x = x, (rect).y = y,\
  34.    (rect).width = width, (rect).height = height)
  35.  
  36. /* Write a rectangle. */
  37. private int
  38. cmd_size_rect(register const gx_cmd_rect *prect)
  39. {    return
  40.       cmd_sizew(prect->x) + cmd_sizew(prect->y) +
  41.       cmd_sizew(prect->width) + cmd_sizew(prect->height);
  42. }
  43. private byte *
  44. cmd_put_rect(register const gx_cmd_rect *prect, register byte *dp)
  45. {    cmd_putw(prect->x, dp);
  46.     cmd_putw(prect->y, dp);
  47.     cmd_putw(prect->width, dp);
  48.     cmd_putw(prect->height, dp);
  49.     return dp;
  50. }
  51.  
  52. int
  53. cmd_write_rect_cmd(gx_device_clist_writer *cldev, gx_clist_state *pcls,
  54.   int op, int x, int y, int width, int height)
  55. {    int dx = x - pcls->rect.x;
  56.     int dy = y - pcls->rect.y;
  57.     int dwidth = width - pcls->rect.width;
  58.     int dheight = height - pcls->rect.height;
  59. #define check_range_xy(rmin, rmax)\
  60.   ((unsigned)(dx - rmin) <= (rmax - rmin) &&\
  61.    (unsigned)(dy - rmin) <= (rmax - rmin))
  62. #define check_range_w(rmin, rmax)\
  63.   ((unsigned)(dwidth - rmin) <= (rmax - rmin))
  64. #define check_ranges(rmin, rmax)\
  65.   (check_range_xy(rmin, rmax) && check_range_w(rmin, rmax) &&\
  66.    (unsigned)(dheight - rmin) <= (rmax - rmin))
  67.     cmd_set_rect(pcls->rect);
  68.     if ( dheight == 0 && check_range_w(cmd_min_dw_tiny, cmd_max_dw_tiny) &&
  69.          check_range_xy(cmd_min_dxy_tiny, cmd_max_dxy_tiny)
  70.        )
  71.       {    byte op_tiny = op + 0x20 + dwidth - cmd_min_dw_tiny;
  72.         byte *dp;
  73.  
  74.         if ( dx == width - dwidth && dy == 0 )
  75.           { set_cmd_put_op(dp, cldev, pcls, op_tiny + 8, 1);
  76.           }
  77.         else
  78.           { set_cmd_put_op(dp, cldev, pcls, op_tiny, 2);
  79.             dp[1] = (dx << 4) + dy - (cmd_min_dxy_tiny * 0x11);
  80.           }
  81.       }
  82. #define rmin cmd_min_short
  83. #define rmax cmd_max_short
  84.     else if ( check_ranges(rmin, rmax) )
  85.        {    int dh = dheight - cmd_min_dxy_tiny;
  86.         byte *dp;
  87.         if ( (unsigned)dh <= cmd_max_dxy_tiny - cmd_min_dxy_tiny &&
  88.              dh != 0 && dy == 0
  89.            )
  90.            {    op += dh;
  91.             set_cmd_put_op(dp, cldev, pcls, op + 0x10, 3);
  92.             if_debug3('L', "    rs2:%d,%d,0,%d\n",
  93.                   dx, dwidth, dheight);
  94.            }
  95.         else
  96.            {    set_cmd_put_op(dp, cldev, pcls, op + 0x10, 5);
  97.             if_debug4('L', "    rs4:%d,%d,%d,%d\n",
  98.                   dx, dwidth, dy, dheight);
  99.             dp[3] = dy - rmin;
  100.             dp[4] = dheight - rmin;
  101.            }
  102.         dp[1] = dx - rmin;
  103.         dp[2] = dwidth - rmin;
  104.        }
  105. #undef rmin
  106. #undef rmax
  107.     else if ( dy >= -2 && dy <= 1 && dheight >= -2 && dheight <= 1 &&
  108.           (dy + dheight) != -4
  109.         )
  110.       {    byte *dp;
  111.         int rcsize = 1 + cmd_sizew(x) + cmd_sizew(width);
  112.         set_cmd_put_op(dp, cldev, pcls,
  113.                    op + ((dy + 2) << 2) + dheight + 2, rcsize);
  114.         ++dp;
  115.         cmd_put2w(x, width, dp);
  116.       }
  117.     else
  118.        {    byte *dp;
  119.         int rcsize = 1 + cmd_size_rect(&pcls->rect);
  120.         set_cmd_put_op(dp, cldev, pcls, op, rcsize);
  121.         if_debug5('L', "    r%d:%d,%d,%d,%d\n",
  122.               rcsize - 1, dx, dwidth, dy, dheight);
  123.         cmd_put_rect(&pcls->rect, dp + 1);
  124.        }
  125.     return 0;
  126. }
  127.  
  128. /* ---------------- Driver procedures ---------------- */
  129.  
  130. int
  131. clist_fill_rectangle(gx_device *dev, int x, int y, int width, int height,
  132.   gx_color_index color)
  133. {    fit_fill(dev, x, y, width, height);
  134.     BEGIN_RECT
  135.     cmd_disable_lop(cdev, pcls);
  136.     if ( color != pcls->colors[1] )
  137.       {    int code = cmd_put_color(cdev, pcls, &clist_select_color1,
  138.                      color, &pcls->colors[1]);
  139.         if ( code < 0 )
  140.           return code;
  141.       }
  142.     { int code = cmd_write_rect_cmd(cdev, pcls, cmd_op_fill_rect, x, y,
  143.                     width, height);
  144.       if ( code < 0 )
  145.         return code;
  146.     }
  147.     END_RECT
  148.     return 0;
  149. }
  150.  
  151. int
  152. clist_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tile,
  153.   int x, int y, int width, int height,
  154.   gx_color_index color0, gx_color_index color1, int px, int py)
  155. {    int depth =
  156.       (color1 == gx_no_color_index && color0 == gx_no_color_index ?
  157.        dev->color_info.depth : 1);
  158.  
  159.     fit_fill(dev, x, y, width, height);
  160.     BEGIN_RECT
  161.     ulong offset_temp;
  162.  
  163.     cmd_disable_lop(cdev, pcls);
  164.     if ( !cls_has_tile_id(cdev, pcls, tile->id, offset_temp) )
  165.        {    if ( tile->id == gx_no_bitmap_id ||
  166.              clist_change_tile(cdev, pcls, tile, depth) < 0
  167.            )
  168.           {    int code =
  169.               gx_default_strip_tile_rectangle(dev, tile,
  170.                         x, y, width, height,
  171.                         color0, color1, px, py);
  172.             if ( code < 0 )
  173.               return code;
  174.             goto endr;
  175.           }
  176.        }
  177.     if ( color0 != pcls->tile_colors[0] || color1 != pcls->tile_colors[1] )
  178.       {    int code = cmd_set_tile_colors(cdev, pcls, color0, color1);
  179.         if ( code < 0 )
  180.           return code;
  181.       }
  182.     if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
  183.       {    int code = cmd_set_tile_phase(cdev, pcls, px, py);
  184.         if ( code < 0 )
  185.           return code;
  186.       }
  187.     { int code = cmd_write_rect_cmd(cdev, pcls, cmd_op_tile_rect, x, y,
  188.                     width, height);
  189.       if ( code < 0 )
  190.         return code;
  191.     }
  192. endr:    ;
  193.     END_RECT
  194.     return 0;
  195. }
  196.  
  197. int
  198. clist_copy_mono(gx_device *dev,
  199.     const byte *data, int data_x, int raster, gx_bitmap_id id,
  200.     int x, int y, int width, int height,
  201.     gx_color_index color0, gx_color_index color1)
  202. {    int y0;
  203.     gx_bitmap_id orig_id = id;
  204.  
  205.     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
  206.     y0 = y;
  207.     BEGIN_RECT
  208.     int dx = data_x & 7;
  209.     int w1 = dx + width;
  210.     const byte *row = data + (y - y0) * raster + (data_x >> 3);
  211.     int code;
  212.  
  213.     cmd_disable_lop(cdev, pcls);
  214.     cmd_disable_clip(cdev, pcls);
  215.     if ( color0 != pcls->colors[0] )
  216.       {    code = cmd_set_color0(cdev, pcls, color0);
  217.         if ( code < 0 )
  218.           return code;
  219.       }
  220.     if ( color1 != pcls->colors[1] )
  221.       {    code = cmd_set_color1(cdev, pcls, color1);
  222.         if ( code < 0 )
  223.           return code;
  224.       }
  225.     /* Don't bother to check for a possible cache hit: */
  226.     /* tile_rectangle and fill_mask handle those cases. */
  227. copy:    {    gx_cmd_rect rect;
  228.         int rsize;
  229.         byte op = (byte)cmd_op_copy_mono;
  230.         byte *dp;
  231.         uint csize;
  232.         int code;
  233.  
  234.         rect.x = x, rect.y = y;
  235.         rect.width = w1, rect.height = height;
  236.         rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
  237.         code = cmd_put_bits(cdev, pcls, row, w1, height, raster,
  238.                     rsize, (orig_id == gx_no_bitmap_id ?
  239.                         1 << cmd_compress_rle :
  240.                         cmd_mask_compress_any),
  241.                     &dp, &csize);
  242.         if ( code < 0 )
  243.           { if ( code != gs_error_limitcheck )
  244.               return code;
  245.             /* The bitmap was too large; split up the transfer. */
  246.             if ( height > 1 )
  247.               {    /* Split the transfer by reducing the height.
  248.              * See the comment above BEGIN_RECT in gxcldev.h.
  249.              */
  250.             height >>= 1;
  251.             goto copy;
  252.               }
  253.             {    /* Split a single (very long) row. */
  254.             int w2 = w1 >> 1;
  255.             code = clist_copy_mono(dev, row, dx + w2,
  256.                 raster, gx_no_bitmap_id, x + w2, y,
  257.                 w1 - w2, 1, color0, color1);
  258.             if ( code < 0 )
  259.               return code;
  260.             w1 = w2;
  261.             goto copy;
  262.             }
  263.           }
  264.         op += code;
  265.         if ( dx )
  266.           { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
  267.             *dp++ = cmd_set_misc_data_x + dx;
  268.           }
  269.         *dp++ = cmd_count_op(op, csize);
  270.         cmd_put2w(x, y, dp);
  271.         cmd_put2w(w1, height, dp);
  272.         pcls->rect = rect;
  273.        }
  274.     END_RECT
  275.     return 0;
  276. }
  277.  
  278. int
  279. clist_copy_color(gx_device *dev,
  280.   const byte *data, int data_x, int raster, gx_bitmap_id id,
  281.   int x, int y, int width, int height)
  282. {    int depth = dev->color_info.depth;
  283.     int y0;
  284.     int data_x_bit;
  285.  
  286.     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
  287.     y0 = y;
  288.     data_x_bit = data_x * depth;
  289.     BEGIN_RECT
  290.     int dx = (data_x_bit & 7) / depth;
  291.     int w1 = dx + width;
  292.     const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
  293.     int code;
  294.  
  295.     cmd_disable_lop(cdev, pcls);
  296.     cmd_disable_clip(cdev, pcls);
  297.     if ( pcls->color_is_alpha )
  298.       { byte *dp;
  299.         set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_color, 1);
  300.         pcls->color_is_alpha = 0;
  301.       }
  302. copy:      {    gx_cmd_rect rect;
  303.         int rsize;
  304.         byte op = (byte)cmd_op_copy_color_alpha;
  305.         byte *dp;
  306.         uint csize;
  307.  
  308.         rect.x = x, rect.y = y;
  309.         rect.width = w1, rect.height = height;
  310.         rsize = (dx ? 3 : 1) + cmd_size_rect(&rect);
  311.         code = cmd_put_bits(cdev, pcls, row, w1 * depth,
  312.                     height, raster, rsize,
  313.                     1 << cmd_compress_rle, &dp, &csize);
  314.         if ( code < 0 )
  315.           { if ( code != gs_error_limitcheck )
  316.               return code;
  317.             /* The bitmap was too large; split up the transfer. */
  318.             if ( height > 1 )
  319.               {    /* Split the transfer by reducing the height.
  320.              * See the comment above BEGIN_RECT in gxcldev.h.
  321.              */
  322.             height >>= 1;
  323.             goto copy;
  324.               }
  325.             {    /* Split a single (very long) row. */
  326.             int w2 = w1 >> 1;
  327.             code = clist_copy_color(dev, row, dx + w2,
  328.                 raster, gx_no_bitmap_id, x + w2, y,
  329.                 w1 - w2, 1);
  330.             if ( code < 0 )
  331.               return code;
  332.             w1 = w2;
  333.             goto copy;
  334.             }
  335.           }
  336.         op += code;
  337.         if ( dx )
  338.           { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
  339.             *dp++ = cmd_set_misc_data_x + dx;
  340.           }
  341.         *dp++ = cmd_count_op(op, csize);
  342.         cmd_put2w(x, y, dp);
  343.         cmd_put2w(w1, height, dp);
  344.         pcls->rect = rect;
  345.  
  346.       }
  347.     END_RECT
  348.     return 0;
  349. }
  350.  
  351. int
  352. clist_copy_alpha(gx_device *dev, const byte *data, int data_x,
  353.   int raster, gx_bitmap_id id, int x, int y, int width, int height,
  354.   gx_color_index color, int depth)
  355. {    /* I don't like copying the entire body of clist_copy_color */
  356.     /* just to change 2 arguments and 1 opcode, */
  357.     /* but I don't see any alternative that doesn't require */
  358.     /* another level of procedure call even in the common case. */
  359.     int log2_depth = depth >> 1;    /* works for 1,2,4 */
  360.     int y0;
  361.     int data_x_bit;
  362.  
  363.     fit_copy(dev, data, data_x, raster, id, x, y, width, height);
  364.     y0 = y;
  365.     data_x_bit = data_x << log2_depth;
  366.     BEGIN_RECT
  367.     int dx = (data_x_bit & 7) >> log2_depth;
  368.     int w1 = dx + width;
  369.     const byte *row = data + (y - y0) * raster + (data_x_bit >> 3);
  370.     int code;
  371.  
  372.     cmd_disable_lop(cdev, pcls);
  373.     cmd_disable_clip(cdev, pcls);
  374.     if ( !pcls->color_is_alpha )
  375.       { byte *dp;
  376.         set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
  377.         pcls->color_is_alpha = 1;
  378.       }
  379.     if ( color != pcls->colors[1] )
  380.       {    int code = cmd_set_color1(cdev, pcls, color);
  381.         if ( code < 0 )
  382.           return code;
  383.       }
  384. copy:      {    gx_cmd_rect rect;
  385.         int rsize;
  386.         byte op = (byte)cmd_op_copy_color_alpha;
  387.         byte *dp;
  388.         uint csize;
  389.  
  390.         rect.x = x, rect.y = y;
  391.         rect.width = w1, rect.height = height;
  392.         rsize = (dx ? 4 : 2) + cmd_size_rect(&rect);
  393.         code = cmd_put_bits(cdev, pcls, row, w1 << log2_depth,
  394.                     height, raster, rsize,
  395.                     1 << cmd_compress_rle, &dp, &csize);
  396.         if ( code < 0 )
  397.           { if ( code != gs_error_limitcheck )
  398.               return code;
  399.             /* The bitmap was too large; split up the transfer. */
  400.             if ( height > 1 )
  401.               {    /* Split the transfer by reducing the height.
  402.              * See the comment above BEGIN_RECT in gxcldev.h.
  403.              */
  404.             height >>= 1;
  405.             goto copy;
  406.               }
  407.             {    /* Split a single (very long) row. */
  408.             int w2 = w1 >> 1;
  409.             code = clist_copy_alpha(dev, row, dx + w2,
  410.                 raster, gx_no_bitmap_id, x + w2, y,
  411.                 w1 - w2, 1, color, depth);
  412.             if ( code < 0 )
  413.               return code;
  414.             w1 = w2;
  415.             goto copy;
  416.             }
  417.           }
  418.         op += code;
  419.         if ( dx )
  420.           { *dp++ = cmd_count_op(cmd_opv_set_misc, 2);
  421.             *dp++ = cmd_set_misc_data_x + dx;
  422.           }
  423.         *dp++ = cmd_count_op(op, csize);
  424.         *dp++ = depth;
  425.         cmd_put2w(x, y, dp);
  426.         cmd_put2w(w1, height, dp);
  427.         pcls->rect = rect;
  428.       }
  429.     END_RECT
  430.     return 0;
  431. }
  432.  
  433. int
  434. clist_strip_copy_rop(gx_device *dev,
  435.   const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id,
  436.   const gx_color_index *scolors,
  437.   const gx_strip_bitmap *textures, const gx_color_index *tcolors,
  438.   int x, int y, int width, int height,
  439.   int phase_x, int phase_y, gs_logical_operation_t lop)
  440. {    gs_rop3_t rop = lop_rop(lop);
  441.     gx_strip_bitmap tile_with_id;
  442.     const gx_strip_bitmap *tiles = textures;
  443.     int y0;
  444.  
  445.     if ( scolors != 0 && scolors[0] != scolors[1] )
  446.       { fit_fill(dev, x, y, width, height);
  447.       }
  448.     else
  449.       { fit_copy(dev, sdata, sourcex, sraster, id, x, y, width, height);
  450.       }
  451.     y0 = y;
  452.     /*
  453.      * We shouldn't need to put the logic below inside BEGIN/END_RECT,
  454.      * but the lop_enabled flags are per-band.
  455.      */
  456.     BEGIN_RECT
  457.     const byte *row = sdata + (y - y0) * sraster;
  458.     int code;
  459.  
  460.     if ( rop3_uses_T(rop) )
  461.       { if ( tcolors == 0 || tcolors[0] != tcolors[1] )
  462.           { ulong offset_temp;
  463.             if ( !cls_has_tile_id(cdev, pcls, tiles->id, offset_temp) )
  464.           { /* Change tile.  If there is no id, generate one. */
  465.             if ( tiles->id == gx_no_bitmap_id )
  466.               { tile_with_id = *tiles;
  467.                 tile_with_id.id = gs_next_ids(1);
  468.             tiles = &tile_with_id;
  469.               }
  470.             code = clist_change_tile(cdev, pcls, tiles,
  471.                          (tcolors != 0 ? 1 :
  472.                           dev->color_info.depth));
  473.             if ( code < 0 )
  474.               { /*
  475.              * If the error is a limitcheck, we have a tile that
  476.              * is too big to fit in the command reading buffer.
  477.              * For now, just divide up the transfer into scan
  478.              * lines.  (If a single scan line won't fit, punt.)
  479.              * Eventually, we'll need a way to transfer the tile
  480.              * in pieces.
  481.              */
  482.             uint rep_height = tiles->rep_height;
  483.             gs_id ids;
  484.             gx_strip_bitmap line_tile;
  485.             int iy;
  486.  
  487.             if ( code != gs_error_limitcheck ||
  488.                  rep_height == 1 ||
  489.                  /****** CAN'T HANDLE SHIFT YET ******/
  490.                  tiles->rep_shift != 0
  491.                )
  492.               return code;
  493.             /*
  494.              * Allocate enough fake IDs, since the inner call on
  495.              * clist_strip_copy_rop will need them anyway.
  496.              */
  497.             ids = gs_next_ids(min(height, rep_height));
  498.             line_tile = *tiles;
  499.             line_tile.size.y = 1;
  500.             line_tile.rep_height = 1;
  501.             for ( iy = 0; iy < height; ++iy )
  502.               { line_tile.data = tiles->data + line_tile.raster *
  503.                   ((y + iy + phase_y) % rep_height);
  504.                 line_tile.id = ids + (iy % rep_height);
  505.                 /*
  506.                  * Note that since we're only transferring
  507.                  * a single scan line, phase_y is irrelevant;
  508.                  * we may as well use the current tile phase
  509.                  * so we don't have to write extra commands.
  510.                  */
  511.                 code = clist_strip_copy_rop(dev,
  512.                 (sdata == 0 ? 0 : row + iy * sraster),
  513.                 sourcex, sraster,
  514.                 gx_no_bitmap_id, scolors, &line_tile, tcolors,
  515.                 x, y + iy, width, 1,
  516.                 phase_x, pcls->tile_phase.y, lop);
  517.                 if ( code < 0 )
  518.                   return code;
  519.               }
  520.             continue;
  521.               }
  522.             if ( phase_x != pcls->tile_phase.x ||
  523.              phase_y != pcls->tile_phase.y
  524.                )
  525.               { code = cmd_set_tile_phase(cdev, pcls, phase_x,
  526.                           phase_y);
  527.                 if ( code < 0 )
  528.               return code;
  529.               }
  530.           }
  531.           }
  532.         /* Set the tile colors. */
  533.         code = (tcolors != 0 ?
  534.             cmd_set_tile_colors(cdev, pcls, tcolors[0], tcolors[1]) :
  535.             cmd_set_tile_colors(cdev, pcls, gx_no_color_index,
  536.                     gx_no_color_index));
  537.         if ( code < 0 )
  538.           return code;
  539.       }
  540.     if ( lop != pcls->lop )
  541.       { code = cmd_set_lop(cdev, pcls, lop);
  542.         if ( code < 0 )
  543.           return code;
  544.       }
  545.     cmd_enable_lop(cdev, pcls);
  546.     /* Set lop_enabled to -1 so that fill_rectangle / copy_* */
  547.     /* won't attempt to set it to 0. */
  548.     pcls->lop_enabled = -1;
  549.     if ( scolors != 0 )
  550.       { if ( scolors[0] == scolors[1] )
  551.           code = clist_fill_rectangle(dev, x, y, width, height,
  552.                       scolors[1]);
  553.         else
  554.           code = clist_copy_mono(dev, row, sourcex, sraster, id,
  555.                      x, y, width, height,
  556.                      scolors[0], scolors[1]);
  557.       }
  558.     else
  559.       code = clist_copy_color(dev, row, sourcex, sraster, id,
  560.                   x, y, width, height);
  561.     pcls->lop_enabled = 1;
  562.     if ( code < 0 )
  563.       return code;
  564.     END_RECT
  565.     return 0;      
  566. }
  567.